前言
Javascript
提供了三种主要的值比较运算符:
- 严格相等(三等)
===
- 宽松相等(两等)
==
Object.is()
除此之外,JavaScript
内部还使用了四种不同的相等算法:
- 宽松相等
- 严格相等
- 同值相等
- 零值相等
使用严格相等
严格相等是最常用的比较方式。它在比较两个值之前不会进行隐式类型转换,要求两者的类型和值完全相同。
值得注意的是,数组中的索引查找(如
Array.prototype.indexOf
)也使用严格相等进行匹配。
test.ts
console.log(+0 === -0) // true
console.log(NaN === NaN) // false
const array = [NaN]
array.indexOf(NaN) // -1
在上例中,虽然 NaN
不等于自身,但 Array.prototype.indexOf
使用严格相等,因此找不到 NaN
。
使用宽松相等
宽松相等允许在比较值之前执行隐式类型转换,根据值的类型进行适当的规则处理。以下是宽松相等的一些规则:
- 如果操作数类型相等,则按以下方式比较
- 对象:两个操作数是同一引用返回
true
- 字符串: 两个操作数字符串相等返回
true
- 数字: 值相等,
-0
与+0
被视为相同的值,NaN
永远不等于自身 - 布尔:值相等
BigInt
:值相等Symbol
:两个操作数引用相同的符号返回true
- 对象:两个操作数是同一引用返回
null
与undefined
:两个操作数必须都是null
与undefined
- 对象与原始值:对象需要进行原始值强制转换1
- 两个对象都不是原始值,需要将两个操作数都变成原始值进行比较
console.log(5 == 5) // true
console.log('abc' == 'abc') // true
console.log(null == undefined) // true
console.log(undefined == 0) // false 对于第2点
console.log(true == 1) // true,true 转换为 1
console.log(false == 0) // true,false 转换为 0
console.log(true == 0) // false
console.log(5 == '5') // true,字符串 '5' 转换为数字 5
console.log(5 == 'abc') // false,'abc' 转换失败为 NaN
console.log(5 == 5n) // true,直接按数值比较
console.log(5 == NaN) // false,NaN 不等于任何值
从这些例子中可以看到,宽松相等可能因为隐式类型转换导致一些意想不到的结果,因此在实际开发中应尽量避免使用。
同值相等比较 Object.is
Object.is
提供了一种更精确的比较方式,称为同值相等。与严格相等类似,但有两点区别:
- 不会进行隐式类型转换。
- 对于
NaN
和-0
/+0
的处理更加精准:
- NaN 被视为等于自身。
-0
和+0
被视为不相等。
console.log(Object.is(NaN, NaN))
// Expected output: true
console.log(Object.is(-0, 0))
// Expected output: false
零值相等 SameValueZero
类似于同值相等,相对于严格相等 NaN
被视作相等的,同时与同值相等的区别 -0
与 +0
被视作相等的。与此对应的是Array.prototype.includes
采用这种比较方式来检查数组中是否包含某个值2。
const array = [NaN, -0]
console.log(array.includes(NaN)) // true
console.log(array.includes(+0)) // true
console.log(array.includes(-0)) // true
使用场景
零值相等被设计为更适合实际场景的算法,特别是在列表操作中,比如检查元素存在性。
何时使用 Object.is
- 需要对
NaN
进行相等的场景,以及-0
与+0
不等的情况 - 宽松比较涉及隐式转换场景,无法区分类型
- 严格比较需要同类型,但是无法区分
0
的正负,以及NaN
被视作不相等 - 同值比较需要值相等,可以区分
0
的正负,NaN
被视作相等 - 零值相等类似同值相等,无法区分
0
的正负,NaN
被视作相等
x | y | == | === | Object.is | SameValueZero |
---|---|---|---|---|---|
+0 | -0 | true | true | false | true |
NaN | NaN | false | false | true | true |
总结
严格相等适用于大多数场景,因其行为明确且避免隐式类型转换。
宽松相等存在隐式类型转换,不建议在现代开发中使用。
Object.is
提供了精准的比较方式,适合对 NaN
和 -0
/+0
敏感的情况。
零值相等是数组查找和存在性判断的理想选择,避免了 NaN
和 -0
/+0
的常见问题。
选择正确的比较方式,不仅能提高代码的准确性和可维护性,还能帮助避免潜在的 Bug。